package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"text/template"
	"time"
)

var (
	h       bool
	t       string
	outPath string
)

func init() {
	flag.BoolVar(&h, "h", false, "this help")
	flag.StringVar(&t, "t", "template", "指定模版目录，默认是 template 目录")
	flag.Usage = usage
}

func usage() {
	fmt.Printf(`t2c 代码生成器 version: 0.1
Usage: t2c [-h] [-t templatePath]

文件会生成在模板目录下的 out 目录。例如 template/out

Options:
`)
	flag.PrintDefaults()
}

func main() {
	flag.Parse()
	if h {
		usage()
		return
	}
	cleanOutPath()
	env := loadEnv()
	templates := env.Templates
	for _, tpl := range templates {
		filename := getFilename(tpl.Path, env)
		fmt.Printf("使用 %v 生成 %v\n", tpl.Name, filename)
		fileContent := buildFileContent(tpl.Name, env)
		createDir(filename)
		createFile(filename, fileContent)
	}
	fmt.Println("生成完成")
}

func cleanOutPath() {
	outPath = getTemplatePath() + "out/"
	_ = os.RemoveAll(outPath)
}

type Env struct {
	Env       map[string]string            `json:"Env"`
	Map       map[string]map[string]string `json:"Map"`
	Templates []Tpl                        `json:"Templates"`
}

type Tpl struct {
	Path string `json:"Path"`
	Name string `json:"Name"`
}

func getTemplatePath() string {
	return "./" + t + "/"
}

func loadEnv() Env {
	//应该是 绝对地址
	jsonStr, err := ioutil.ReadFile(getTemplatePath() + "env.json")
	if err != nil {
		fmt.Println(err.Error())
	}

	var env Env
	err = json.Unmarshal(jsonStr, &env)

	if err != nil {
		panic(fmt.Sprintf("读取配置文件失败"))
	}

	return env
}

func buildFileContent(tplName string, env Env) *bytes.Buffer {
	parseFiles, err := createTemplate(tplName, env).ParseFiles(getTemplatePath() + "tpl/" + tplName)
	if err != nil {
		panic(fmt.Sprintf("解析模版错误:%v", err.Error()))
	}
	fileContent := new(bytes.Buffer)
	if err := parseFiles.Execute(fileContent, env.Env); err != nil {
		panic(fmt.Sprintf("解析模版错误:%v", err.Error()))
	}
	return fileContent
}

func createFile(filename string, fileContent *bytes.Buffer) bool {
	target, err := os.Create(filename)
	if err != nil {
		panic(fmt.Sprintf("创建文件[%v]失败:%v", filename, err))
	}
	_, err = target.WriteString(fileContent.String())
	if err != nil {
		panic(fmt.Sprintf("写入文件失败"))
	}
	if err = target.Close(); err != nil {
		return true
	}
	return false
}

func createTemplate(templateName string, env Env) *template.Template {
	return template.New(templateName).Funcs(template.FuncMap{
		"lower": func(str string) string {
			return strings.ToLower(str)
		},
		"map": func(dict, key string) string {
			m, ok := env.Map[dict]
			if !ok {
				return "未定义的字典"
			}
			v, ok := m[key]
			if !ok {
				return "找不到值"
			}
			return v
		},
		"upper": func(str string) string {
			return strings.ToUpper(str)
		},
		"today": func() string {
			return time.Now().Format("2006-01-02")
		},
		"now": func() string {
			return time.Now().Format("2006-01-02 15:04:05")
		},
		"camelToPascar": CamelToPascar,
		"pascarToCamel": PascarToCamel,
	})
}

func CamelToPascar(source string) string {
	return strings.ToUpper(string(source[0])) + source[1:]
}

func PascarToCamel(source string) string {
	return strings.ToLower(string(source[0])) + source[1:]
}

func getFilename(filenameExpr string, env Env) string {
	tpl, _ := createTemplate("filename", env).Parse(filenameExpr)
	filename := new(bytes.Buffer)
	err := tpl.Execute(filename, env.Env)
	if err != nil {
		panic(fmt.Sprintf("解析文件名失败:%v", filename.String()))
	}
	return outPath + filename.String()
}

func createDir(filename string) {
	path := filepath.Dir(filename)
	fmt.Println(path)
	err := os.MkdirAll(path, 0750)
	if err != nil {
		panic(fmt.Sprintf("创建文件目录[%v]失败:%v", path, err))
	}
}
